package org.gwtde.client.views;

import java.util.HashMap;
import java.util.Map;

import net.mygwt.ui.client.Events;
import net.mygwt.ui.client.Registry;
import net.mygwt.ui.client.event.BaseEvent;
import net.mygwt.ui.client.event.Listener;
import net.mygwt.ui.client.event.ShellListener;
import net.mygwt.ui.client.mvc.AppEvent;
import net.mygwt.ui.client.mvc.Controller;
import net.mygwt.ui.client.mvc.Dispatcher;
import net.mygwt.ui.client.mvc.View;
import net.mygwt.ui.client.util.Rectangle;
import net.mygwt.ui.client.widget.DesktopShell;
import net.mygwt.ui.client.widget.Shell;
import net.mygwt.ui.client.widget.ToolButton;

import org.gwtde.client.Desktop;
import org.gwtde.client.DesktopEvents;
import org.gwtde.client.model.AppLink;

import com.google.gwt.user.client.ui.Frame;

public class ShellView extends View {

	private static Map sShellNames = new HashMap();

	private String mURL;
	private Shell mShell;
	private Frame mFrame;

	private boolean mMaximized = false;
	private boolean mRolledUp = false;
	private Rectangle mOldBounds = null;

	ShellListener mListener = new ShellListener() {
		public void shellDeactivated(BaseEvent be) {
			Shell shell = (Shell) be.widget;
			Dispatcher.forwardEvent(new AppEvent(
					DesktopEvents.ShellDeActivated, shell));
		}

		public void shellClosed(BaseEvent be) {
			Shell shell = (Shell) be.widget;
			sShellNames.remove(shell.getText());
			Dispatcher.forwardEvent(new AppEvent(DesktopEvents.ShellClosed,
					shell));
		}

		public void shellActivated(BaseEvent be) {
			Shell shell = (Shell) be.widget;
			Dispatcher.forwardEvent(new AppEvent(DesktopEvents.ShellActivated,
					shell));
		}
	};

	public ShellView(Controller pController) {
		super(pController);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.mygwt.ui.client.mvc.View#initialize()
	 */
	protected void initialize() {
		final Rectangle desktopBounds = Desktop.getBounds();

		mShell = new DesktopShell();
		mShell.setData(this);

		mShell.setSize((int) (Desktop.getClientWidth() / 1.5), (int) (Desktop
				.getClientHeight() / 1.333));

		mShell.setIconStyle("icon-shell");
		mShell.setText("GWT Desktop Shell");

		mShell.getContent().addStyleName("gwtde-shell-content");

		final DockView dock = (DockView) Registry.get("dock");

		ToolButton refresh = new ToolButton("my-tool-refresh");
		refresh.setTitle("Reload current shell");
		refresh.addListener(Events.Click, new Listener() {
			public void handleEvent(BaseEvent be) {
				mFrame.setUrl(mURL);
			}
		});
		mShell.getHeader().addWidget(refresh);

		final ToolButton roll = new ToolButton("my-tool-minus");
		roll.setTitle("Roll up current shell");
		roll.addListener(Events.Click, new Listener() {
			public void handleEvent(BaseEvent be) {
				if (mRolledUp) {
					if (mMaximized) {
						mShell.setHeight(Desktop.getClientHeight());
					} else if (mOldBounds != null) {
						mShell.setHeight(mOldBounds.height);
						mOldBounds = null;
					} else {
						mShell
								.setHeight((int) (Desktop.getClientHeight() / 1.333));
					}
					mRolledUp = false;
					roll.changeStyle("my-tool-minus");
				} else {
					if (!mMaximized) {
						mOldBounds = mShell.getBounds();
					}
					mShell.setHeight(50);
					mRolledUp = true;
					roll.changeStyle("my-tool-plus");
				}
			}
		});
		// mShell.getHeader().addWidget(roll);

		final ToolButton minimize = new ToolButton("my-tool-minimize");
		minimize.setTitle("Minimize current shell");
		minimize.addListener(Events.Click, new Listener() {
			public void handleEvent(BaseEvent be) {
				mShell.hide();
			}
		});
		mShell.getHeader().addWidget(minimize);

		final ToolButton resize = new ToolButton("my-tool-maximize");
		resize.setTitle("Maximize/Restore current shell");
		resize.addListener(Events.Click, new Listener() {
			public void handleEvent(BaseEvent be) {

				if (mMaximized) {
					if (mOldBounds != null) {
						mShell.setBounds(mOldBounds);
						mOldBounds = null;
					} else {
						mShell.setSize((int) (Desktop.getClientWidth() / 1.5),
								(int) (Desktop.getClientHeight() / 1.333));
						mShell.center();
					}
					mMaximized = false;
					resize.changeStyle("my-tool-maximize");
					mRolledUp = false;
					roll.changeStyle("my-tool-minus");
				} else {
					if (!mRolledUp) {
						mOldBounds = mShell.getBounds();
					}
					Rectangle r = dock.getBounds();
					if (dock.isPinned() && (r.x - desktopBounds.x) == 0) {
						mShell.setBounds(new Rectangle(desktopBounds.x
								+ r.width, desktopBounds.y, Desktop
								.getClientWidth()
								- r.width, Desktop.getClientHeight()));
					} else if (dock.isPinned()) {
						mShell.setBounds(new Rectangle(desktopBounds.x,
								desktopBounds.y, Desktop.getClientWidth()
										- r.width, Desktop.getClientHeight()));
					} else {
						mShell.setBounds(new Rectangle(desktopBounds.x,
								desktopBounds.y, Desktop.getClientWidth(),
								Desktop.getClientHeight()));
					}
					mMaximized = true;
					resize.changeStyle("my-tool-restore");
					mRolledUp = false;
					roll.changeStyle("my-tool-minus");
				}
				mShell.setResizeEnabled(!mMaximized);
				mShell.setDragEnabled(!mMaximized);
			}
		});
		mShell.getHeader().addWidget(resize);

		mShell.addShellListener(mListener);
		mShell.addListener(Events.Resize, new Listener() {
			public void handleEvent(BaseEvent be) {
				mRolledUp = false;
				roll.changeStyle("my-tool-minus");
				mOldBounds = null;
			}
		});
		mShell.getDraggable().container = Desktop.getContainer();

		mShell.open();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.mygwt.ui.client.mvc.ViewhandleEvent(net.mygwt.ui.client.mvc.AppEvent)
	 */
	protected void handleEvent(AppEvent pEvent) {
		switch (pEvent.type) {
		case DesktopEvents.ShellOpenURL:
			AppLink link = (AppLink) pEvent.data;
			String name = link.getName();
			for (int i = 1; sShellNames.get(name) != null; i++) {
				name = link.getName() + " [" + i + "]";
			}
			sShellNames.put(name, mShell);
			
			mShell.setText(name);
			mURL = link.getURL();
			mFrame = mShell.setURL(mURL);
			
			mShell.getContent().layout(true);
			
			Dispatcher.forwardEvent(new AppEvent(DesktopEvents.ShellCreated,
					mShell));
			break;
		case DesktopEvents.DockPinned:
			if (mMaximized) {
				handleDockPinned();
			}
			break;
		case DesktopEvents.DockUnPinned:
			if (mMaximized) {
				handleDockUnPinned();
			}
			break;
		}
	}

	private void handleDockPinned() {
		final Rectangle desktopBounds = Desktop.getBounds();
		final DockView dock = (DockView) Registry.get("dock");
		Rectangle r = dock.getBounds();
		if (r.x - desktopBounds.x == 0) {
			mShell.setBounds(new Rectangle(desktopBounds.x + r.width,
					desktopBounds.y, Desktop.getClientWidth() - r.width,
					Desktop.getClientHeight()));
		} else {
			mShell.setBounds(new Rectangle(desktopBounds.x, desktopBounds.y,
					Desktop.getClientWidth() - r.width, Desktop
							.getClientHeight()));
		}
	}

	private void handleDockUnPinned() {
		final Rectangle desktopBounds = Desktop.getBounds();
		mShell.setBounds(new Rectangle(desktopBounds.x, desktopBounds.y,
				Desktop.getClientWidth(), Desktop.getClientHeight()));

	}
}
